import sets

from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.contrib.auth.decorators import login_required


from wjContact.contacts.models import Contact, Recipient, Volunteer
from wjContact.contacts.views.forms import ContactForm, RecipientForm
from wjContact.contacts.views.forms import VolunteerForm
from wjContact.contacts.views.forms import SearchForm



##============================================================================##
## Ajax views
## ===========================================================================##

def ajax_suburb_autocomplete(request):
  if request.GET.has_key('q'):
    suburbs = PCSuburb.objects.filter(name__istartswith=request.GET['q'])[:10]
    return HttpResponse('\n'.join(suburb.name for suburb in suburbs))

  return HttpResponse()  


##============================================================================##
## Index and Search views
## ===========================================================================##    
        
       #Under Construction! 
        

##============================================================================##
## Methods and views which user multi-table forms
##============================================================================##

def save_and_redirect(request, form, redirect_to=None, msg='Saved'):
    form.save()
    msg = " %s" % msg
    request.user.message_set.create(message=msg)
    return HttpResponseRedirect(redirect_to) 

##============================================================================##
## Contact Views
##============================================================================##

def contact_edit(request, main_object_id=None):
    return contact(request, main_object_id=main_object_id)
    
def contact(request, main_object_id=None):
    """ """
    ## See contrib/admin/views.main.add_stage() for some ideas...   
    ## If user has hit the submit button, the request method will be 'POST'...
    if request.method == 'POST':
        ## The following works whether we are an adding form or an editing
        ## form.
        for key in request.POST.keys():
            ## The key should be 'add_another_pet', 'add_another_phone', etc
            if key.startswith('add_another'):
                base_name = key.split('_')[2]
                plural_name = base_name + 's'
                request_data = dict(request.POST)
                new_request_data = {}
                for key in request_data:
                    new_request_data[key] = request_data[key][0]   
                if main_object_id:
                    ## we are editing.      
                    object = Contact.objects.get(pk=main_object_id)                 
                    filled_form = ContactForm(initial=new_request_data, main_object=object)
                else:
                    ## we are adding.
                    filled_form = ContactForm(initial=new_request_data)
                    
                filled_form.__getattribute__(plural_name).add_fields(1)
                filled_form.put_fieldlists_into_form_fields()      
                ff=filled_form  ## FIXME: I think this line may just be debug code
                msg = "Here are the additional entry fields you asked for..."
                request.user.message_set.create(message=msg)
                return render_to_response(
                  'contact.html', 
                  {'form' : filled_form},
                  context_instance=RequestContext(request)
                  )          
        if main_object_id:
            ## We are an editing form    
            object = Contact.objects.get(pk=main_object_id)  
            filled_form =  ContactForm(request.POST, main_object=object)
        else:
             ## We are an adding form       
            filled_form = ContactForm(request.POST)
        ## handle_contact_form does validation and re-rendering or directing on. 
        ff=filled_form  ## FIXME: I think this line may just be debug code
        ##process_form(request, filled_form, template, redirect_to):  
#        template = "contact.html"
#        redirect_to = "http://localhost:8000/contacts/contacts"
        #return process_form(request, filled_form, template, redirect_to)                
        return handle_contact_form(request, filled_form)   
    ## If request.method is not 'POST', then the user has not yet hit the 
    ## submit button  -->  render an empty form for them to fill in ...       
    else:  
        if main_object_id:   
            object = Contact.objects.get(pk=main_object_id)
            empty_form = ContactForm(main_object=object)
            form_instructions = "Edit or update existing details here!"
        else:
            empty_form = ContactForm()
            form_instructions = "Add a new Contact here.  A contact can be a donor, recycler, service person, supplier, open source software contact etc. "
    ef=empty_form    
    return render_to_response(
        'contact.html', 
        {
         'form' : empty_form,
         'form_instructions': form_instructions,
         },
        context_instance=RequestContext(request)
        )                                     
contact = login_required(contact) 

def handle_contact_form(request, filled_form): 
    """
    Check that the filled form is valid, and check for duplicates. 
    
     1. If everything checks out ok: get the form to save() itself and return
        the 'save and redirect' method.
     2. If there are duplicates, instead render a page listing these.
     3. If the form data is invalid in some way, re-render the form with the
        error messages displayed, so that the user can fix them.
     """
    ff = filled_form ## FIXME: I think this line is just debug code...
    if not (filled_form.is_valid()):
        ## If it's not valid, render failure message
        msg = "Couldn't add new contact using the details given. Please fix the problems I've listed below and I'll try again :)"
        request.user.message_set.create(message=msg)
        return render_to_response('contact.html',
             {'form': filled_form}, 
             context_instance=RequestContext(request) )  
    ## Check that this entry does not duplicate an existing one...
    ## The check_for_duplicates() method returns either an appropriate
    ## response object, which is 'True', and we pass it on, or else it 
    ## returns None. Should consider refactoring
    ## this, to keep views type stuff out of the file.
    ## Only check for duplicates if we are adding a new entry, not if we are
    ## updating an existing one.
    ## FIXME: Fix the redirect URL!
    contacts_list_url = "/contacts/contacts"
    ## FIXME use string.join() rather than string concatenation.
    contact_fullname = filled_form.clean_data['first_name'] + ' ' + filled_form.clean_data['last_name']
    msg = "Saved changes for user %s." % contact_fullname
    saver = save_and_redirect(request, filled_form, redirect_to = contacts_list_url, msg=msg)
    ## And if there are no duplicates, save the data from this form 
    ## to the database, and redirect to the list of all existing 
    ## contacts. Always return an HttpResponseRedirect after 
    ## successfully dealing with POST data. This prevents data from 
    ## being posted twice if a user hits the Back button. 
    return saver
 
def contact_list(request):
    """ List all Contacts."""
    contacts = Contact.objects.all().order_by('last_name')
    return render_to_response(
        'contact_list.html', 
        {'contact_list': contacts},
        context_instance=RequestContext(request))    
##============================================================================##
## Recipient Views
##============================================================================##
def recipient_edit(request, main_object_id=None):
    return recipient(request, main_object_id=main_object_id)
    
def recipient(request, main_object_id=None):
    """ """
    ## See contrib/admin/views.main.add_stage() for some ideas...   
    ## If user has hit the submit button, the request method will be 'POST'...
    ## The following works whether we are an adding form or an editing
    ## form.
    if request.method == 'POST':     
        for key in request.POST.keys():
            ## The key should be 'add_another_pet', 'add_another_phone', etc
            if key.startswith('add_another'):
                base_name = key.split('_')[2]
                plural_name = base_name + 's'
                request_data = dict(request.POST)
                new_request_data = {}
                for key in request_data:
                    new_request_data[key] = request_data[key][0]   
                if main_object_id:
                    ## we are editing.    
                    ## Get the contact object corresponding to this recipient.
                    ##  
                    object = Contact.objects.get(contact__exact=main_object_id)                 
                    filled_form = RecipientForm(initial=new_request_data, main_object=object)
                else:
                    ## we are adding.
                    filled_form = RecipientForm(initial=new_request_data)
                    
                filled_form.__getattribute__(plural_name).add_fields(1)
                filled_form.put_fieldlists_into_form_fields()
                ff=filled_form ## FIXME: I think this line may just be debug code
                msg = "Here are the additional entry fields you asked for..."
                request.user.message_set.create(message=msg)
                return render_to_response(
                  'recipient.html', 
                  {'form' : filled_form},
                  context_instance=RequestContext(request)
                  )          
        if main_object_id:
            ## We are an editing form    
            object = Recipient.objects.get(contact__exact=main_object_id)  
            filled_form = RecipientForm(request.POST, main_object=object)
        else:
             ## We are an adding form       
            filled_form = RecipientForm(request.POST)
        ## handle_recipient_form does validation and re-rendering or directing on. 
        ff=filled_form     ## FIXME: I think this line may just be debug code               
        return handle_recipient_form(request, filled_form)   
    ## If request.method is not 'POST', then the user has not yet hit the 
    ## submit button  -->  render either an empty form for them to fill in (if
    ## we are adding) or else render a form prefilled with existing data from
    ## the daabase (if we are editing)...       
    else:  
        if main_object_id:   
            ## We are editing
            object = Recipient.objects.get(contact__exact=main_object_id)
            empty_form = RecipientForm(main_object=object)
            form_instructions = "Edit an existing Recipient here!"
        else:
            ## We are adding
            empty_form = RecipientForm()
            form_instructions = "Add new Recipient details on this form"
    ef=empty_form   
    return render_to_response(
        'recipient.html', 
        {
         'form' : empty_form,
         'form_instructions': form_instructions,
         },
        context_instance=RequestContext(request)
        )                                     
recipient = login_required(recipient) 

def handle_recipient_form(request, filled_form): 
    """
    Check that the filled form is valid, and check for duplicates. 
    
     1. If everything checks out ok: get the form to save() itself and return
        the 'save and redirect' method.
     2. If there are duplicates, instead render a page listing these.
     3. If the form data is invalid in some way, re-render the form with the
        error messages displayed, so that the user can fix them.
     """
    if not (filled_form.is_valid()):
        ## If it's not valid, render failure message
        msg = "Couldn't add new recipient using the details given. Please fix the problems listed below and I'll try again :)"
        request.user.message_set.create(message=msg)
        return render_to_response('recipient.html',
             {'form': filled_form}, 
             context_instance=RequestContext(request) )  
    ## Check that this entry does not duplicate an existing one...
    ## The check_for_duplicates() method returns either an appropriate
    ## response object, which is 'True', and we pass it on, or else it 
    ## returns None. Should consider refactoring
    ## this, to keep views type stuff out of the file.
    ## Only check for duplicates if we are adding a new entry, not if we are
    ## updating an existing one.
    recipient = filled_form.save()
    fname = filled_form.clean_data['first_name']
    lname = filled_form.clean_data['last_name']
    msg = "New recipient %s %s successfully added." % (fname, lname)
    request.user.message_set.create(message=msg)
    if 'add_and_continue' in request.POST.keys():
        #return sale_edit(request, recipient_id=recipient.id)   
        #post_url_continue='../%s/'
        post_url_continue="/recipient/%s/sales_add/"
        return HttpResponseRedirect(post_url_continue % recipient.id)
        #return HttpResponseRedirect(post_url_continue % pk_value)
    else:   
        redirect_to = "/contacts/recipients"
        return HttpResponseRedirect(redirect_to)  
         
def recipient_list(request):
    """ List all recipients."""
    recipients = Recipient.objects.all()
    #recipients = Recipient.objects.all().order_by('contacts_contact.last_name')
    #Entry.objects.order_by('blogs_blog.name', 'headline')
    ##FIXME
    ## Pass in a list of (contact, recipient) tuples. This is because some of 
    ## the attributes we will want to display in the list belong to the contact
    ## object (first_name, address, etc), while some belong to the recipient
    ## object (experience, and so on).   
    contacts_and_recipients = []
    for recipient in recipients:
        contact = Contact.objects.get(id=recipient.contact_id)
        contacts_and_recipients.append((contact, recipient))
    return render_to_response(
        'recipient_list.html', 
        {'contacts_and_recipients_list': contacts_and_recipients},
        context_instance=RequestContext(request))    
     
##============================================================================##
## Volunteer Views
##============================================================================##
def volunteer_edit(request, main_object_id=None):
    return volunteer(request, main_object_id=main_object_id)

def volunteer(request, main_object_id=None):
    """ """
    ## See contrib/admin/views.main.add_stage() for some ideas...   
    ## If user has hit the submit button, the request method will be 'POST'...
    if request.method == 'POST':
        ## The following works whether we are an adding form or an editing
        ## form.
        for key in request.POST.keys():
            ## The key should be 'add_another_pet', 'add_another_phone', etc
            if key.startswith('add_another'):
                base_name = key.split('_')[2]
                plural_name = base_name + 's'
                request_data = dict(request.POST)
                new_request_data = {}
                for key in request_data:
                    new_request_data[key] = request_data[key][0]   
                if main_object_id:
                    ## we are editing.      
                    object = Contact.objects.get(pk=main_object_id)                 
                    filled_form = VolunteerForm(initial=new_request_data, main_object=object)
                else:
                    ## we are adding.
                    filled_form = VolunteerForm(initial=new_request_data)
                    
                filled_form.__getattribute__(plural_name).add_fields(1)
                filled_form.put_fieldlists_into_form_fields()      
                ff=filled_form  ## FIXME: I think this line may just be debug code
                msg = "Here are the additional entry fields you asked for..."
                request.user.message_set.create(message=msg)
                return render_to_response(
                  'volunteer.html', 
                  {'form' : filled_form},
                  context_instance=RequestContext(request)
                  )          
        if main_object_id:
            ## We are an editing form    
            object = Volunteer.objects.get(pk=main_object_id)  
            filled_form =  VolunteerForm(request.POST, main_object=object)
        else:
             ## We are an adding form       
            filled_form = VolunteerForm(request.POST)
        ## handle_volunteer_form does validation and re-rendering or directing on. 
        ff=filled_form  ## FIXME: I think this line may just be debug code
        ##process_form(request, filled_form, template, redirect_to):  
#        template = "volunteer.html"
#        redirect_to = "http://localhost:8000/contacts/volunteers"
        #return process_form(request, filled_form, template, redirect_to)                
        return handle_volunteer_form(request, filled_form)   
    ## If request.method is not 'POST', then the user has not yet hit the 
    ## submit button  -->  render an empty form for them to fill in ...       
    else:  
        if main_object_id:   
            object = Volunteer.objects.get(pk=main_object_id)
            empty_form = VolunteerForm(main_object=object)
            form_instructions = "Edit an existing Volunteer here!"
        else:
            empty_form = VolunteerForm()
            form_instructions = "Add Volunteer details here!"
    ef=empty_form    
    return render_to_response(
        'volunteer.html', 
        {
         'form' : empty_form,
         'form_instructions': form_instructions,
         },
        context_instance=RequestContext(request)
        )                                     
volunteer = login_required(volunteer) 

def handle_volunteer_form(request, filled_form): 
    """
    Check that the filled form is valid, and check for duplicates. 
    
     1. If everything checks out ok: get the form to save() itself and return
        the 'save and redirect' method.
     2. If there are duplicates, instead render a page listing these.
     3. If the form data is invalid in some way, re-render the form with the
        error messages displayed, so that the user can fix them.
     """
    ff = filled_form ## FIXME: I think this line is just debug code...
    if not (filled_form.is_valid()):
        ## If it's not valid, render failure message
        msg = "Couldn't add new volunteer using the details given. Please fix the problems I've listed below and I'll try again :)"
        request.user.message_set.create(message=msg)
        return render_to_response('volunteer.html',
             {'form': filled_form}, 
             context_instance=RequestContext(request) )  
    ## Check that this entry does not duplicate an existing one...
    ## The check_for_duplicates() method returns either an appropriate
    ## response object, which is 'True', and we pass it on, or else it 
    ## returns None. Should consider refactoring
    ## this, to keep views type stuff out of the file.
    ## Only check for duplicates if we are adding a new entry, not if we are
    ## updating an existing one.
    ## FIXME: Fix the redirect URL!
    volunteers_list_url = "/contacts/volunteers"
    ## FIXME use string.join() rather than string concatenation.
    volunteer_fullname = filled_form.clean_data['first_name'] + ' ' + filled_form.clean_data['last_name']
    msg = "Saved changes for %s." % volunteer_fullname
    saver = save_and_redirect(request, filled_form, redirect_to = volunteers_list_url, msg=msg)
    ## And if there are no duplicates, save the data from this form 
    ## to the database, and redirect to the list of all existing 
    ## volunteers. Always return an HttpResponseRedirect after 
    ## successfully dealing with POST data. This prevents data from 
    ## being posted twice if a user hits the Back button. 
    return saver

def volunteer_list(request):
    """ List all Volunteers."""
    ##FIXME
    ## Pass in a list of (contact, volunteer) tuples. This is because some of 
    ## the attributes we will want to display in the list belong to the contact
    ## object (first_name, address, etc), while some belong to the volunteer
    ## object (interests, and so on).
    volunteers = Volunteer.objects.all()
    contacts_and_volunteers = []
    for volunteer in volunteers:
        contact = Contact.objects.get(id=volunteer.contact_id)
        contacts_and_volunteers.append((contact, volunteer))
    return render_to_response(
        'volunteer_list.html', 
        {'contacts_and_volunteers_list': contacts_and_volunteers},
        context_instance=RequestContext(request))    
    
   
def search(request):
    form = SearchForm()

    contacts =[]
    show_results = False

    if request.GET.has_key('query') or request.GET.has_key('querylastname'):
        """
        #this code works to search for firstname
        show_results = True
        contacts = Contact.objects

        queryfirstname = request.GET['query'].strip()
        if queryfirstname:
            form = SearchForm({'query': queryfirstname})
            contacts = contacts.filter(first_name__icontains=queryfirstname)

        """

        show_results = True
        query = request.GET['query'].strip()
        if query:
            form = SearchForm({'query': query})
            
            querywords = query.split() #contains list of user search terms
            queryResultList = []       #contains list of Contact set of results for each query word term
            queryResultSet = set()     #contains result set that contains all contacts in user search
            for word in querywords:
                contacts_first_name = Contact.objects.filter(first_name__icontains=word)
                contacts_last_name  = Contact.objects.filter(last_name__icontains=word)
                contacts_suburb = Contact.objects.filter(suburb__icontains=word)
                queryResultList.append(set(contacts_first_name) | set(contacts_last_name) | set(contacts_suburb))
            
            ## Note from wendy: I'm not sure what is meant to be tested for in 
            ## the following, but it looks to me like queryResultList will 
            ## never have a length greater then 1. This is because the line 
            ## above, where it says:
            ## queryResultList.append(set(..) | set(..) | set(..))
            ## will always amalgamate the three sets into one *before* 
            ## appending the result onto the queryResultList. Thus the test
            ## below may be unecessary, as th 'else' clause will never occur
            ## anyway. However I am not totally sure, and since it isn't 
            ## hurting anything, I'll leave as is for the moment. <wsl>
            if len(queryResultList) == 1:
                #just return the only entry in the list 
                queryResultSet = queryResultList[0]
            else:
                #we know there are at least two entries, so we find the collisions
                #print queryResultList[0]
                #print queryResultList[1]
                queryResultSet = queryResultList[0] & queryResultList[1]
                print queryResultList[1]
                for i in queryResultList:
                    queryResultSet = queryResultSet & i 
            contacts = list(queryResultSet)
        

    #contacts = contacts[:10] #list only last 10 entries
    variables = RequestContext(request, {
                'form': form,
                'contacts': contacts,
                'contact_list': contacts,
                'show_results': show_results,
            })
    return render_to_response('search_contacts.html', variables)

#==============================================================================#
